#include "libcomm.h"

CommTime Timer::Now()
{
	CommTime now;;
#ifdef COMM_MSVC
	SYSTEMTIME localtm;
	::GetLocalTime(&localtm);
	now.year = localtm.wYear;
	now.month = localtm.wMonth;
	now.day = localtm.wDay;
	now.wday = localtm.wDayOfWeek;
	now.hour = localtm.wHour;
	now.minute = localtm.wMinute;
	now.second = localtm.wSecond;
	now.microsecond = localtm.wMilliseconds*1000;
#else
	struct timeval tv;
	MYLIB_ASSERT_ERRNO(0 == gettimeofday(&tv, NULL));
	struct tm* localtm = localtime(&tv.tv_sec);
	now.year = localtm->tm_year + 1900;
	now.month = localtm->tm_mon+1;
	now.day = localtm->tm_mday;
	now.wday = localtm->tm_wday;
	now.hour = localtm->tm_hour;
	now.minute = localtm->tm_min;
	now.second = localtm->tm_sec;
	now.microsecond = tv.tv_usec;
#endif
	return now;
}

#ifndef COMM_MSVC
#if 0
// POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead.
timespec Timer::MakeTimespec(unsigned int timeoutMs)
{
	struct timespec ts;
	{
		struct timeval now;
		{
			MYLIB_ASSERT_ERRNO(0 == gettimeofday(&now, NULL));
			now.tv_usec += timeoutMs * 1000;
			if (now.tv_usec >= 1000000)
			{
				now.tv_sec += now.tv_usec / 1000000;
				now.tv_usec %= 1000000;
			}
		}
		ts.tv_sec = now.tv_sec;
		ts.tv_nsec = now.tv_usec * 1000;
	}
	return ts;
}
#else
timespec Timer::MakeTimespec(unsigned int timeoutMs)
{
	struct timespec absTime;
	MYLIB_ASSERT_ERRNO(0 == clock_gettime(CLOCK_REALTIME, &absTime));

	absTime.tv_sec += timeoutMs / 1000;
	absTime.tv_nsec += (timeoutMs % 1000) * 1000000;

	if (absTime.tv_nsec >= 1000000000)
	{
		absTime.tv_sec += 1;
		absTime.tv_nsec -= 1000000000;
	}
	return absTime;
}
#endif
#endif

//////////////////////////////////////////////////////////////////////////

Timer::Timer(bool startup)
{
	m_time[0] = m_time[1] = m_time[2] = 0;
#ifdef COMM_MSVC
	LARGE_INTEGER nFreq;
	MYLIB_ASSERT(QueryPerformanceFrequency(&nFreq));
	m_time[2] = nFreq.QuadPart;
#endif
	if (startup)
		Start();
}

void Timer::Start()
{
#ifdef COMM_MSVC
	LARGE_INTEGER nStart;
	MYLIB_ASSERT(QueryPerformanceCounter(&nStart));
	m_time[0] = nStart.QuadPart;
#else
	struct timeval tv;
	MYLIB_ASSERT_ERRNO(0 == gettimeofday(&tv, NULL));
	m_time[0] = tv.tv_sec * 1000000 + tv.tv_usec;
#endif
}

void Timer::Stop()
{
#ifdef COMM_MSVC
	LARGE_INTEGER nEnd;
	MYLIB_ASSERT(QueryPerformanceCounter(&nEnd));
	m_time[1] = nEnd.QuadPart;
#else
	struct timeval tv;
	MYLIB_ASSERT_ERRNO(0 == gettimeofday(&tv, NULL));
	m_time[1] = tv.tv_sec * 1000000 + tv.tv_usec;
#endif
}

long long Timer::Elapse()
{
	long long diff = 0;
#ifdef COMM_MSVC
	diff = (m_time[1] - m_time[0]) * 1000000 / m_time[2];
#else
	diff = m_time[1] - m_time[0];
#endif
	return diff;
}

////////////////////////////////////////////////////////////////////////// TimeCounter

TimeCounter::TimeCounter(Timer* timer):m_timer(timer)
{
	MYLIB_ASSERT_NOTNULL(m_timer);
	m_timer->Start();
}

TimeCounter::~TimeCounter()
{
	m_timer->Stop();
}